// Agent serveur in project restaurant.mas2j
// Projet a rendre pour le 22 janvier, soutenance le 28

//Le serveur va s'enregistrer aupres de l'environnement qui va lui attribuer un numero.
//Ensuite le serveur va garder en memoire les commandes qui lui ont ete passees et qu'il a prises
//dans le detail, mais aussi les commandes dont il ne s'est pas occupe ainsi que le numero du serveur qui s'en est charge


/* Initial beliefs and rules */

//serveurEnAttente.

/* Initial goals */

!start.
!termineAction.

/* Plans */

//Bidouille pour ne pas dupliquer la position
+!start : serveurLocation(Abscisse,Ordonnee) <- 	+selfLocation(Abscisse,Ordonnee); confirmeEnregistreServeur(Abscisse, Ordonnee).

+!start : not serveurLocation(Abscisse,Ordonnee) <- 	enregistreServeur; !start.

//Liste des actions a effectuer si le serveur passe en attente
+!termineAction : commandeEnAttente(IdCommande, NomServeur,Table) <- -commandeEnAttente(IdCommande, NomServeur,Table);
!traiteCommande(IdCommande, NomServeur,Table).

+!termineAction : tousEntrees(IdCommande, pret)[source(Chef)] & commandeAttribuee(IdCommande, MonNom, Table) & selfServeur(MonNom) <- 
!gereDistribution( tousEntrees, IdCommande, Table, pret,Chef).


+!termineAction : tousPlats(IdCommande, pret)[source(Chef)] & commandeAttribuee(IdCommande, MonNom, Table) & selfServeur(MonNom) <- 
!gereDistribution( tousPlats, IdCommande, Table, pret,Chef).

+!termineAction : tousDesserts(IdCommande, pret)[source(Chef)] & commandeAttribuee(IdCommande, MonNom, Table) & selfServeur(MonNom) <- 
!gereDistribution( tousDesserts, IdCommande, Table, pret,Chef).

+!termineAction : selfLocation(A,B) & case(A,B+1,guichet) <- +serveurEnAttente.

+!termineAction <- !moveTo(guichet); !termineAction.



+serveurEnAttente : demandeAttributionCommande(K,T) <- demandeAttributionCommande(K,T).

+serveurEnAttente : tousEntrees(IdCommande, pret)[source(Chef)] & commandeAttribuee(IdCommande, MonNom, Table) & selfServeur(MonNom) <- 
-serveurEnAttente; !gereDistribution( tousEntrees, IdCommande, Table, pret,Chef).

+serveurEnAttente :  tousPlats(IdCommande, pret)[source(Chef)] & commandeAttribuee(IdCommande, MonNom, Table) & selfServeur(MonNom) <- 
-serveurEnAttente; !gereDistribution( tousPlats, IdCommande, Table, pret,Chef).

+serveurEnAttente : tousDesserts(IdCommande, pret)[source(Chef)] & commandeAttribuee(IdCommande, MonNom, Table) & selfServeur(MonNom) <- 
-serveurEnAttente; !gereDistribution( tousDesserts, IdCommande, Table, pret,Chef).

+serveurEnAttente : not (demandeAttributionCommande(_,_)) & not (tousEntrees(_, _)) & not (tousPlats(_, _)) & not (tousDesserts(_, _))<-
-serveurEnAttente; .wait(100); +serveurEnAttente. 

+selfServeur(NomServeur) <- .print("Serveur ", NomServeur, " enregistre").

//K : identifiant de la nouvelle commande, T : table d'où est partie la commande
+nouvelleCommande(IdCommande, Table) : serveurEnAttente <- +demandeAttributionCommande(IdCommande, Table);
											demandeAttributionCommande(IdCommande, Table).

+nouvelleCommande(IdCommande, Table) : not serveurEnAttente <- +demandeAttributionCommande(IdCommande, Table).

//systeme d'attribution des commandes
+commandeAttribuee(IdCommande, NomServeur,Table) : selfServeur(MonNom) & not(NomServeur==MonNom) <- -demandeAttributionCommande(IdCommande, Table).

+commandeAttribuee(IdCommande, NomServeur,Table) : selfServeur(MonNom) & serveurEnAttente <- -serveurEnAttente;
											-demandeAttributionCommande(IdCommande, Table);
											.print("Commande ",IdCommande," attribuee au serveur ",MonNom);
											!traiteCommande(IdCommande, NomServeur,Table).

//TODO: bug, si la commande est attribuée et que le serveur n'est pas en attente											
											
											
+commandeAttribuee(IdCommande, MonNom, Table) : selfServeur(MonNom) & not serveurEnAttente <- -demandeAttributionCommande(IdCommande, Table); 
.print("Commande ",IdCommande," en attente pour le serveur ",Table);
+commandeEnAttente(IdCommande, MonNom, Table).
					
//Système de traitement des commandes, incluant le déplacement a la table concernée
											
+!traiteCommande(IdCommande, MonNom, Table) : selfServeur(MonNom) <- !moveTo(Table);
											enregistreCommande(IdCommande);
											.print("Commande ",IdCommande," enregistree par le serveur ",MonNom);
											!transmetCommande(IdCommande);
											!termineAction.


// Bidouille : replication de la base de connaissances pour permettre au serveur de supprimer des connaissances
// sur les commandes passees
+nouvelleCommande(IdCommande,enAttente,MonNom) : selfServeur(MonNom) <- +commande(IdCommande,enAttente,MonNom).
+nouvelleEntree(IdCommande,DetailCommande,PositionSurTable,enregistre,MonNom) : selfServeur(MonNom) <- +entree(IdCommande,DetailCommande,PositionSurTable,enregistre,MonNom).
+nouveauPlat(IdCommande,DetailCommande,PositionSurTable,enregistre,MonNom) : selfServeur(MonNom) <- +plat(IdCommande,DetailCommande,PositionSurTable,enregistre,MonNom).
+nouveauDessert(IdCommande,DetailCommande,PositionSurTable,enregistre,MonNom) : selfServeur(MonNom) <- +dessert(IdCommande,DetailCommande,PositionSurTable,enregistre,MonNom).
						

+!transmetCommande(IdCommande) : selfLocation(Abscisse, Ordonnee) & fonction(Chef,chef) & case(Abscisse,Ordonnee-1,Chef) <-
.print("Commande ",IdCommande," transmise a ",Chef); 
.send(Chef, tell, commandeAPreparer(IdCommande));
!decritCommande(IdCommande,Chef).
											
+!transmetCommande(IdCommande) <- !moveTo(chef) ; !transmetCommande(IdCommande).

// Communication entre le serveur et le chef Y pour transmettre la commande X
+!decritCommande(IdCommande,Chef) : selfServeur(MonNom) & entree(IdCommande,DetailCommande,PositionSurTable,enregistre,MonNom) <-
-entree(IdCommande,DetailCommande,PositionSurTable,enregistre,MonNom);
.send(Chef,tell, entree(IdCommande,DetailCommande,PositionSurTable,enCours,MonNom));
+entree(IdCommande,DetailCommande,PositionSurTable,transmis,MonNom);
!decritCommande(IdCommande,Chef).

+!decritCommande(IdCommande,Chef) : selfServeur(MonNom) & plat(IdCommande,DetailCommande,PositionSurTable,enregistre,MonNom) <-
-plat(IdCommande,DetailCommande,PositionSurTable,enregistre,MonNom);
.send(Chef,tell, plat(IdCommande,DetailCommande,PositionSurTable,enCours,MonNom));
+plat(IdCommande,DetailCommande,PositionSurTable,transmis,MonNom);
!decritCommande(IdCommande,Chef).

+!decritCommande(IdCommande,Chef) : selfServeur(MonNom) & dessert(IdCommande,DetailCommande,PositionSurTable,enregistre,MonNom) <-
-dessert(IdCommande,DetailCommande,PositionSurTable,enregistre,MonNom);
.send(Chef,tell, dessert(IdCommande,DetailCommande,PositionSurTable,enCours,MonNom));
+dessert(IdCommande,DetailCommande,PositionSurTable,transmis,MonNom);
!decritCommande(IdCommande,Chef).

+!decritCommande(IdCommande,Chef) : selfServeur(MonNom) <- -commande(IdCommande,enAttente,MonNom);  +commande(IdCommande,transmise,MonNom).

//***********************************************************************************************************
// Système permettant a un serveur d'aller chercher une commande auprès d'un cuisinier et de l'amener a table
//***********************************************************************************************************

// Le chef va envoyer au serveur une connaissance du type de celle qui est ci dessous : 
//+entree(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier) <- !gereDistribution (entree(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier)).
//+plat(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier) <- !gereDistribution (plat(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier)).
//+dessert(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier) <- !gereDistribution (dessert(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier)).
+entree(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier) : selfServeur(Serveur) <-
-entree(IdCommande, DetailCommande, PositionSurTable, transmis, Serveur).

+plat(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier) : selfServeur(Serveur) <-
-plat(IdCommande, DetailCommande, PositionSurTable, transmis, Serveur).

+dessert(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier) : selfServeur(Serveur) <-
-dessert(IdCommande, DetailCommande, PositionSurTable, transmis, Serveur).


+!gereDistributionPlat( entree(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier,Chef)) :
selfLocation(A,B)  <-
!moveTo(NomCuisinier); -entree(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier)[source(Chef)];
prendCommandeAuCuisinier(IdCommande,A,B,NomCuisinier);
.print("a pris l'entree numero ",PositionSurTable," de la commande ",IdCommande," au cuisinier ",NomCuisinier);
+manger(IdCommande, DetailCommande, PositionSurTable, entree).

+!gereDistributionPlat( plat(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier,Chef)) : selfLocation(A,B) <-
!moveTo(NomCuisinier); -plat(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier)[source(Chef)];
prendCommandeAuCuisinier(IdCommande,A,B,NomCuisinier);
.print("a pris le plat numero ",PositionSurTable," de la commande ",IdCommande," au cuisinier ",NomCuisinier);
+manger(IdCommande, DetailCommande, PositionSurTable, plat).

+!gereDistributionPlat( dessert(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier,Chef)) : selfLocation(A,B) <-
!moveTo(NomCuisinier); -dessert(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier)[source(Chef)];
prendCommandeAuCuisinier(IdCommande,A,B,NomCuisinier);
.print("a pris le desert numero ",PositionSurTable," de la commande ",IdCommande," au cuisinier ",NomCuisinier);
+manger(IdCommande, DetailCommande, PositionSurTable, dessert).

//Il faut servir tous les types de plats en meme temps.

+tousEntrees(IdCommande, pret)[source(Chef)] : serveurEnAttente & commandeAttribuee(IdCommande, MonNom, Table) & selfServeur(MonNom) <-
!gereDistribution(tousEntrees,IdCommande, Table, pret,Chef).

+tousPlats(IdCommande, pret)[source(Chef)]   : serveurEnAttente & commandeAttribuee(IdCommande, MonNom, Table) & selfServeur(MonNom) <- 
!gereDistribution( tousPlats,IdCommande, Table, pret,Chef).

+tousDesserts(IdCommande, pret)[source(Chef)] : serveurEnAttente & commandeAttribuee(IdCommande, MonNom, Table) & selfServeur(MonNom) <- 
!gereDistribution( tousDesserts, IdCommande, Table, pret,Chef).

+!gereDistribution(tousEntrees,IdCommande, Table, pret,Chef) : entree(IdCommande, Detail, PositionSurTable, pret, NomCuisinier) <-
.print("coin");!gereDistributionPlat(entree(IdCommande, Detail, PositionSurTable, pret, NomCuisinier,Chef));
//.abolish(entree(IdCommande, Detail, PositionSurTable, pret, NomCuisinier));
!gereDistribution(tousEntrees, IdCommande,Table, pret,Chef).

//+!gereDistribution(tousEntrees,IdCommande, Table, pret,Chef) :  not entree(IdCommande, Detail, PositionSurTable, pret, NomCuisinier) <-
+!gereDistribution(tousEntrees,IdCommande, Table, pret,Chef) <-
!moveTo(Table);
-tousEntrees(IdCommande, pret)[source(Chef)];
!distribueCommande(IdCommande,Table, entree).

+!gereDistribution(tousPlats, IdCommande, Table, pret, Chef) : plat(IdCommande, Detail, PositionSurTable, pret, NomCuisinier) <-
!gereDistributionPlat(plat(IdCommande, Detail, PositionSurTable, pret, NomCuisinier,Chef));
//.abolish(plat(IdCommande, Detail, PositionSurTable, pret, NomCuisinier));
!gereDistribution(tousPlats, IdCommande,Table, pret,Chef).

//+!gereDistribution(tousPlats, IdCommande, Table, pret,Chef) : not plat(IdCommande, Detail, PositionSurTable, pret, NomCuisinier) <-
+!gereDistribution(tousPlats, IdCommande, Table, pret,Chef) <-
!moveTo(Table); 
-tousPlats(IdCommande, pret)[source(Chef)];
!distribueCommande(IdCommande,Table, plat).

+!gereDistribution(tousDesserts, IdCommande,Table, pret,Chef) : dessert(IdCommande, DetailCommande, PositionSurTable, pret, NomCuisinier)[source(Chef)] <-
!gereDistributionPlat(dessert(IdCommande, Detail, PositionSurTable, pret, NomCuisinier,Chef));
//.abolish(dessert(IdCommande, Detail, PositionSurTable, pret, NomCuisinier));
!gereDistribution(tousDesserts, IdCommande, Table, pret,Chef).

//+!gereDistribution(tousDesserts, IdCommande, Table, pret,Chef) : not dessert(IdCommande, Detail, PositionSurTable, pret, NomCuisinier) <-
+!gereDistribution(tousDesserts, IdCommande, Table, pret,Chef) <-
!moveTo(Table); 
-tousDesserts(IdCommande, pret)[source(Chef)];
!distribueCommande(IdCommande, Table , dessert).


//Une fois a la table avec les plats en main, on les sert un par un
+!distribueCommande(IdCommande,Table,TypePlat) : manger(IdCommande,Detail,PositionSurTable,TypePlat) <-
.print(IdCommande, " ", Detail, " ", PositionSurTable," ",TypePlat);
-manger(IdCommande,Detail,PositionSurTable,TypePlat);
distribueCommande(IdCommande,Table,TypePlat,PositionSurTable);
.print("distribue le plat ",TypePlat," ",Detail," a la position ",PositionSurTable," de la table ",Table);
!distribueCommande(IdCommande,Table,TypePlat).

+!distribueCommande(IdCommande,Table,TypePlat) : not manger(IdCommande,Detail,PositionSurTable,TypePlat) <- !termineAction.


//Systeme de deplacement, transparent pour un utilisateur (il suffit de faire moveTo(table1) par exemple)

//Cas particulier : si un serveur va voir un chef il choisit aléatoirement lequel des deux il va voir.
//Il peut se dérouter au besoin
+!moveTo(chef) : fonction(Chef,chef) & fonction(NomAutreChef,chef)
& not(Chef==NomAutreChef) & case(AbscisseChef,OrdonneeChef,Chef) & case(AbscisseChef,OrdonneeChef+1,vide) & .random(X) & (X< 0.5) <-
+destination(chef) ; !moveTo(AbscisseChef, OrdonneeChef+1); -destination(chef).

+!moveTo(chef) : fonction(Chef,chef) & fonction(NomAutreChef,chef)
& not(Chef==NomAutreChef) & case(AbscisseChef,OrdonneeChef,AutreChef) & case(AbscisseChef,OrdonneeChef+1,vide) & .random(X) & (X< 0.5) <-
+destination(chef) ; !moveTo(AbscisseChef, OrdonneeChef+1); -destination(chef).

+!moveTo(chef) <- !moveTo(chef).

//Cas particulier : si on va au guichet, il faut pouvoir se dérouter (ie changer de guichet)
+!moveTo(guichet) : case(A,B,guichet) & case(C,D,guichet) & case(E,F,guichet) & case(G,H,guichet) & not (A==C) & not(A==E)
& not (A==G) & not(C==E) & not(C==G) & not(E==G) & .random(W) & W > 0.6 & case(A,B-1,vide) <-
+destination(guichet);!moveTo(A,B-1).

+!moveTo(guichet) : case(A,B,guichet) & case(C,D,guichet) & case(E,F,guichet) & case(G,H,guichet) & not (A==C) & not(A==E)
& not (A==G) & not(C==E) & not(C==G) & not(E==G) & .random(W) & W > 0.6 & case(C,D-1,vide) <-
+destination(guichet);!moveTo(C,D-1).

+!moveTo(guichet) : case(A,B,guichet) & case(C,D,guichet) & case(E,F,guichet) & case(G,H,guichet) & not (A==C) & not(A==E)
& not (A==G) & not(C==E) & not(C==G) & not(E==G) & .random(W) & W > 0.6 & case(E,F-1,vide) <-
+destination(guichet);!moveTo(E,F-1).

+!moveTo(guichet) : case(A,B,guichet) & case(C,D,guichet) & case(E,F,guichet) & case(G,H,guichet) & not (A==C) & not(A==E)
& not (A==G) & not(C==E) & not(C==G) & not(E==G) & .random(W) & W > 0.6 & case(G,H-1,vide) <-
+destination(guichet);!moveTo(G,H-1).

+!moveTo(guichet) <- .wait(100); !moveTo(guichet).

//Cas général, utilise pour des deplacements du type moveTo(table1)

+!moveTo(Z) : selfLocation(X,Y) & case(X,Y+1,Z) <- -destination(Z). 
+!moveTo(Z) : selfLocation(X,Y) & case(X,Y-1,Z) <- -destination(Z).
+!moveTo(Z) : selfLocation(X,Y) & case(X+1,Y,Z) <- -destination(Z).
+!moveTo(Z) : selfLocation(X,Y) & case(X-1,Y,Z) <- -destination(Z).

+!moveTo(Z) : case(X,Y,Z) & case(X,Y+1,vide) & .random(W) & (W<0.5)  <-  
.print("move To ",X,",",Y+1);
+destination(Z) ; !moveTo(X,Y+1).

+!moveTo(Z) : case(X,Y,Z) & case(X,Y-1,vide) & .random(W) & (W<0.5) <-
.print("move To ",X,",",Y-1);
+destination(Z) ; !moveTo(X,Y-1).

+!moveTo(Z) : case(X,Y,Z) & case(X-1,Y,vide) & .random(W) & (W<0.5)  <-
.print("move To ",X-1,",",Y);
+destination(Z) ; !moveTo(X-1,Y).

+!moveTo(Z) : case(X,Y,Z) & case(X+1,Y,vide) & .random(W) & (W<0.5) <-
.print("move To ",X+1,",",Y);
+destination(Z) ; !moveTo(X+1,Y).

+!moveTo(Z) <- +destination(Z); .wait(200); !moveTo(Z).

//Attention, bug : si aucune case a proximite n'est libre, aucun plan n'est appliquable, a corriger ulterieurement

//Si on est arrive, le Move s'arrete la
+!moveTo(X,Y) : selfLocation(X,Y) <- -destination(_).

//Si on n'est pas arrive, on bouge sur une case libre et on continue
+!moveTo(X,Y) : selfLocation(A,B) & not cheminBloque(X,Y) & ( not(A == X) | not(B == Y)) <-
moveNextCase(X,Y,A,B);
!changeLocation(A,B);
!moveTo(X,Y).


+!changeLocation(A,B) : plusCourtChemin(est) <- -selfLocation(A,B); +selfLocation(A+1,B).
+!changeLocation(A,B) : plusCourtChemin(ouest) <- -selfLocation(A,B); +selfLocation(A-1,B).
+!changeLocation(A,B) : plusCourtChemin(nord) <- -selfLocation(A,B); +selfLocation(A,B-1).
+!changeLocation(A,B) : plusCourtChemin(sud) <- -selfLocation(A,B); +selfLocation(A,B+1).
+!changeLocation(A,B) : cheminBloque(_,_).



+!moveTo(X,Y) : cheminBloque(X,Y) & destination(Z) <- .print("Chemin bloque, on attend");
-cheminBloque(X,Y); -destination(Z); .random(W); .wait(500+1000*W); !moveTo(Z).

// Si le chemin est bloque, on attend qu'il se debloque
//+!moveTo(X,Y) : cheminBloque(X,Y) & destination(Z) <- .random(W); .print("pas de chemin, en attente"); .wait(500+1000*W); !moveTo(Z).


